package main

import (
	"bytes"
	"compress/gzip"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"mime"
	"os"
	"path/filepath"
	"strings"
	"text/template"
)

const (
	VERSION    = 1
	OUTPUTFILE = "res.go"
	PACKAGE    = "res"
)

type FileData struct {
	Data string
	Name string
	MIME string
	Size int
}

type Params map[string]interface{}

// command-line flag parsing

var (
	optPackage    string
	optOutputFile string
	optGzipd      bool
)

func init() {
	flag.StringVar(&optPackage, "pkg", PACKAGE, "设置包名")
	flag.StringVar(&optOutputFile, "o", "", "输出文件名")
	flag.BoolVar(&optGzipd, "nogzip", true, "使用 gzip 压缩数据")

	flag.Usage = func() {
		fmt.Println("mkbifs version ", VERSION)
		fmt.Println(`mkbifs - 将文件内置于 .go 文件中。by Yuekcc。`)
		fmt.Println("usage:\n\tmkbifs -pkg=<pkg-name> -o=<output.go> input1 input3/ ...")
		fmt.Println("\t-pkg=<package-name>\t设置包名")
		fmt.Println("\t-o=<output-file>\t设置输出文件名")
		fmt.Println("\t-nogzip\t关闭 gzip 数据压缩 ")

	}
}

func res2go(FILES []FileData, fnames []string) []FileData {
	for _, fname := range fnames {

		f, err := os.Open(fname)
		defer f.Close()
		if err != nil {
			log.Fatal(err)
		}

		fi, err := f.Stat()
		if err != nil {
			log.Fatal(err)
		}

		if fi.IsDir() {
			base := fname

			fis, err := f.Readdir(0)
			if err != nil {
				log.Fatal(err)
			}
			var fs []string
			for _, fi := range fis {
				path := filepath.Join(base, fi.Name())
				fs = append(fs, path)
			}
			FILES = res2go(FILES, fs)
		} else {
			file, err := genFileData(fname)
			if err != nil {
				log.Fatal(err)
			}
			FILES = append(FILES, file)
		}

	}
	return FILES
}

func main() {
	// parse command-line
	flag.Parse()

	// need to handle -o flag!
	var output *os.File
	var err error
	output = os.Stdout

	if optOutputFile != "" {
		output, err = os.Create(optOutputFile)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	}

	if optOutputFile == "" {
		optOutputFile = OUTPUTFILE
	}

	// 没有输入参数文件的情况
	if flag.NArg() == 0 {
		fmt.Println("NOTHING INPUT, EXIT.")
		os.Exit(0)
	}

	fnames := flag.Args()

	FILES := []FileData{}

	FILES = res2go(FILES, fnames)

	params := Params{
		"Files":      FILES,
		"OutputFile": optOutputFile,
		"Package":    optPackage,
		"Gzipd":      fmt.Sprintf("%v", optGzipd),
	}
	render(output, PACKAGE, params)
}

func render(output *os.File, pkg string, params Params) {
	t, _ := template.New(pkg).Parse(BIFS_GO_TEMPLATE)
	t.Execute(output, params)
}

// 处理文件为 FileData
func genFileData(path string) (FileData, error) {

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return FileData{}, fmt.Errorf("MKBIFS ERROR. FILE NOT FOUND: %v", path)
	}
	path = strings.Replace(path, "\\", "/", -1)
	fmt.Println("convert " + path)
	name := fmt.Sprintf("%q", path)
	//size := len(content)
	mime := genMIME(path)
	data := encodeData(content) // 将原始数据编码

	return FileData{
		Name: name,
		MIME: mime,
		Data: data,
	}, nil

}

// 编码数据
// []byte(原始数据) -> gzip -> 压缩后数据
//
func encodeData(content []byte) string {
	if optGzipd {
		var buf bytes.Buffer

		gz := gzip.NewWriter(&buf)
		gz.Write(content)
		gz.Close()
		return fmt.Sprintf("%q", buf.Bytes())
	}
	return fmt.Sprintf("%q", content)
}

// 取得 MIME 类型
func genMIME(name string) string {
	ext := filepath.Ext(name)
	_mime := mime.TypeByExtension(ext)
	return fmt.Sprintf("%q", _mime)
}
